importing BablFishPath
authorØyvind Kolås <ok@src.gnome.org>
Sun, 18 Sep 2005 21:00:05 +0000 (21:00 +0000)
committerØyvind Kolås <ok@src.gnome.org>
Sun, 18 Sep 2005 21:00:05 +0000 (21:00 +0000)
16 files changed:
babl/Makefile.am
babl/babl-conversion.c
babl/babl-core.c
babl/babl-db.c
babl/babl-db.h
babl/babl-fish-path.c [new file with mode: 0644]
babl/babl-fish-reference.c [new file with mode: 0644]
babl/babl-fish-simple.c [new file with mode: 0644]
babl/babl-fish.c
babl/babl-format.c
babl/babl-internal.c
babl/babl-internal.h
babl/babl-introspect.c
babl/babl-model.c
babl/babl-sanity.c
babl/babl-type.c

index 2ca82e73b5250afc56d37cd15175914381ace2ca..bcc92a48a2868921ab153a828ed9360735d1a01b 100644 (file)
@@ -15,6 +15,9 @@ c_sources =                           \
        babl-conversion.c               \
        babl-extension.c                \
        babl-fish.c                     \
+       babl-fish-simple.c              \
+       babl-fish-reference.c           \
+       babl-fish-path.c                \
        babl-format.c                   \
        babl-image.c                    \
        babl-internal.c                 \
index d308469fcd24ac19d9c24bf8775f372b16b7cf8b..976f4372f351c8143ab8df84134d158d6c5bd909 100644 (file)
 #include "babl-db.h"
 #include <string.h>
 #include <stdarg.h>
+#include <math.h>
 
 static int 
 each_babl_conversion_destroy (Babl *babl,
                               void *data)
 {
-  babl_free (babl->instance.name);
   babl_free (babl);
   return 0;  /* continue iterating */
 }
@@ -45,37 +45,48 @@ conversion_new (const char        *name,
   babl_assert (source->class_type ==
                destination->class_type);
 
+  babl = babl_malloc (sizeof (BablConversion) + strlen (name) + 1);
+  babl->instance.name = (void *)babl + sizeof (BablConversion);
+  strcpy(babl->instance.name, name);
+
   if (linear)
     {
-      babl = babl_malloc (sizeof (BablConversion));
       babl->class_type      = BABL_CONVERSION_LINEAR;
       babl->conversion.function.linear = linear;
     }
   else if (plane)
     {
-      babl = babl_malloc (sizeof (BablConversion));
       babl->class_type      = BABL_CONVERSION_PLANE;
       babl->conversion.function.plane = plane;
     }
   else if (planar)
     {
-      babl = babl_malloc (sizeof (BablConversion));
       babl->class_type = BABL_CONVERSION_PLANAR;
       babl->conversion.function.planar = planar;
     }
   switch (source->class_type)
     {
       case BABL_TYPE:
-        break;
-      case BABL_MODEL:
-        if (linear)
+        if (linear) /* maybe linear could take a special argument, passed as an
+                       additional key/value pair in the constructor. To cast it
+                       as a generic N-element conversion, thus making it applicable
+                       to being generic for any within model conversion of plain
+                       buffers.
+                     */
           {
-            babl_fatal ("linear support for %s not supported",
+            babl_fatal ("linear conversions not supported for %s",
                         babl_class_name (source->class_type));
           }
-        else if (plane)
+        else if (planar)
           {
-            babl_fatal ("plane support for %s not supported",
+            babl_fatal ("planar conversions not supported for %ssupported",
+                        babl_class_name (source->class_type));
+          }
+        break;
+      case BABL_MODEL:
+        if (plane)
+          {
+            babl_fatal ("plane conversions not supported for %s",
                         babl_class_name (source->class_type));
           }
         break;
@@ -87,32 +98,72 @@ conversion_new (const char        *name,
     }
 
   babl->instance.id            = id;
-  babl->instance.name          = babl_strdup (name);
   babl->conversion.source      = (union Babl*)source;
   babl->conversion.destination = (union Babl*)destination;
-  babl->conversion.error       = 0.0;
+  babl->conversion.error       = -1.0;
+  babl->conversion.cost        = 69;
 
   babl->conversion.pixels      = 0;
   babl->conversion.processings = 0;
 
-  babl_add_ptr_to_list ((void ***)&(source->type.from), babl);
-  
+  if (babl->class_type == BABL_CONVERSION_LINEAR &&
+      BABL(babl->conversion.source)->class_type == BABL_MODEL)
+    {
+       Babl *src_format=NULL;
+       Babl *dst_format=NULL;
+       if (BABL(babl->conversion.source) == babl_model_id (BABL_RGBA))
+         {
+           src_format = babl_format_id (BABL_RGBA_DOUBLE);
+           dst_format = babl_format_with_model_as_type (
+                                BABL(babl->conversion.destination),
+                                babl_type_id (BABL_DOUBLE));
+         }
+       else if (BABL(babl->conversion.destination) == babl_model_id (BABL_RGBA))
+         {
+           src_format = babl_format_with_model_as_type (
+                                BABL(babl->conversion.source),
+                                babl_type_id (BABL_DOUBLE));
+           dst_format = babl_format_id (BABL_RGBA_DOUBLE);
+         }
+       else
+         {
+           babl_fatal ("neither source nor destination model is RGBA (requirement might be temporary)");
+         }
+       babl_conversion_new (
+          src_format,
+          dst_format, 
+          "linear", linear,
+          NULL);
+       babl->conversion.error = 0.0;
+    }
+
   return babl;
 }
 
 static char buf[512]="";
 static char *
-create_name (Babl *source, Babl *destination)
+create_name (Babl *source, Babl *destination, int type)
 {
 
   if (babl_extender ())
     {
-      snprintf (buf, 512-1, "%s : %s to %s", BABL(babl_extender())->instance.name, source->instance.name, destination->instance.name);
+      snprintf (buf, 512-1, "%s : %s%s to %s",
+          BABL(babl_extender())->instance.name,
+          type == BABL_CONVERSION_LINEAR?"":
+          type == BABL_CONVERSION_PLANE?"plane ":
+          type == BABL_CONVERSION_PLANAR?"planar ":"Eeeek! ",
+          source->instance.name,
+          destination->instance.name);
       buf[511]='\0';
     }
   else
     {
-      snprintf (buf, 512-1, "%s to %s", source->instance.name, destination->instance.name);
+      snprintf (buf, 512-1, "%s %s to %s",
+          type == BABL_CONVERSION_LINEAR?"":
+          type == BABL_CONVERSION_PLANE?"plane ":
+          type == BABL_CONVERSION_PLANAR?"planar ":"Eeeek! ",
+          source->instance.name,
+          destination->instance.name);
       buf[511]='\0';
     }
   return buf;
@@ -129,7 +180,7 @@ babl_conversion_new (void *first_arg,
   BablFuncLinear     linear      = NULL;
   BablFuncPlane      plane       = NULL;
   BablFuncPlanar     planar      = NULL;
-
+  int                type        = 0;
   int                got_func    = 0;
   const char        *arg         = first_arg;
 
@@ -144,6 +195,7 @@ babl_conversion_new (void *first_arg,
   assert (BABL_IS_BABL(source));
   assert (BABL_IS_BABL(destination));
   
+  
   while (arg)
     {
      
@@ -192,13 +244,28 @@ babl_conversion_new (void *first_arg,
   assert (source);
   assert (destination);
 
-  babl = conversion_new (create_name (source, destination),
+  if (linear)
+    {
+      type = BABL_CONVERSION_LINEAR;
+    }
+  else if (plane)
+    {
+      type = BABL_CONVERSION_PLANE;
+    }
+  else if (planar)
+    {
+      type = BABL_CONVERSION_PLANAR;
+    }
+  babl = conversion_new (create_name (source, destination, type),
        id, source, destination, linear, plane, planar);
 
   { 
     Babl *ret = babl_db_insert (db, babl);
     if (ret!=babl)
         babl_free (babl);
+    else
+        babl_add_ptr_to_list ((void ***)&(source->type.from), babl);
+
     return ret;
   }
 }
@@ -252,11 +319,13 @@ babl_conversion_planar_process (BablConversion *conversion,
 }
 
 long
-babl_conversion_process (BablConversion *conversion,
-                         void           *source,
-                         void           *destination,
-                         long            n)
+babl_conversion_process (Babl *babl,
+                         void *source,
+                         void *destination,
+                         long  n)
 {
+  BablConversion *conversion = (BablConversion*) babl;
+
   babl_assert (BABL_IS_BABL (conversion));
 
   switch (BABL(conversion)->class_type)
@@ -309,8 +378,10 @@ babl_conversion_process (BablConversion *conversion,
                                                         n);
       break;
     case BABL_CONVERSION_LINEAR:
-      babl_assert (!BABL_IS_BABL (source));
-      babl_assert (!BABL_IS_BABL (destination));
+      /* the assertions relied on a babl_malloc structure 
+       *
+       * babl_assert (!BABL_IS_BABL (source));
+      babl_assert (!BABL_IS_BABL (destination));*/
 
       babl_conversion_linear_process (conversion,
                                       source, 
@@ -325,7 +396,136 @@ babl_conversion_process (BablConversion *conversion,
       return 0;
       break;
   }
+
+  conversion->processings ++;
+  conversion->pixels += n;
   return n;
 }
 
+#define pixels   8192*2
+
+static double *
+test_create (void)
+{
+  double *test;
+  int     i;
+  
+  srandom (20050728);
+
+  test = babl_malloc (sizeof (double) * pixels * 4);
+
+  for (i = 0; i < pixels * 4; i++)
+     test [i] = (double) random () / RAND_MAX;
+
+  return test;
+}
+
+double
+babl_conversion_error (BablConversion *conversion)
+{
+  Babl *fmt_source;
+  Babl *fmt_destination;
+
+  Babl *fmt_rgba_double;
+
+  double   error = 0.0;
+  unsigned int ticks_start = 0;
+  unsigned int ticks_end   = 0;
+  double  *test; 
+  void    *source;
+  void    *destination;
+  double  *destination_rgba_double;
+  void    *ref_destination;
+  double  *ref_destination_rgba_double;
+
+
+  if (!conversion)
+    return 0.0;
+
+  fmt_source      = BABL(conversion->source);
+  fmt_destination = BABL(conversion->destination);
+
+  if (fmt_source == fmt_destination)
+    {
+      conversion->error = 0.0;
+      return 0.0;
+    }
+
+  if (!(fmt_source->instance.id      != BABL_RGBA   &&
+      fmt_destination->instance.id != BABL_RGBA   &&
+      fmt_source->instance.id      != BABL_DOUBLE &&
+      fmt_destination->instance.id != BABL_DOUBLE &&
+      fmt_source->class_type       == BABL_FORMAT &&
+      fmt_destination->class_type  == BABL_FORMAT))
+    {
+      conversion->error = 0.000042;
+    }
+  if (conversion->error != -1.0)  /* double conversion against a set value should work */
+    {
+      return conversion->error;
+    }
+  
+  test=test_create ();
+
+  fmt_rgba_double = babl_format_new (
+       babl_model     ("RGBA"),
+       babl_type      ("double"),
+       babl_component ("R"),
+       babl_component ("G"),
+       babl_component ("B"),
+       babl_component ("A"),
+       NULL);
+
+
+  source          = babl_calloc (pixels, fmt_source->format.bytes_per_pixel);
+  destination     = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel);
+  ref_destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel);
+  destination_rgba_double     = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel);
+  ref_destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel);
+  
+  babl_process (babl_fish_reference (fmt_rgba_double, fmt_source),
+      test, source, pixels);
+
+  ticks_start = babl_ticks ();
+  babl_process (babl_fish_simple (conversion),
+      source, destination, pixels);
+  ticks_end = babl_ticks ();
+
+  babl_process (babl_fish_reference (fmt_source, fmt_destination),
+      source, ref_destination, pixels);
+
+  babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double),
+      ref_destination, ref_destination_rgba_double, pixels);
+  babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double),
+      destination, destination_rgba_double, pixels);
+
+  {
+    int i;
+
+    for (i=0;i<pixels;i++)
+      {
+        int j;
+        for (j=0;j<4;j++)
+            error += fabs (destination_rgba_double[i*4+j] - 
+                            ref_destination_rgba_double[i*4+j]);
+      }
+     error /= pixels;
+     error *= 100;
+  }
+  
+  babl_free (source);
+  babl_free (destination);
+  babl_free (destination_rgba_double);
+  babl_free (ref_destination);
+  babl_free (ref_destination_rgba_double);
+  babl_free (test);
+
+  conversion->error = error;
+  conversion->cost  = ticks_end-ticks_start;
+
+  return error;
+}
+
+
 BABL_CLASS_TEMPLATE (conversion)
index bcc54f9d23b1110e351ea0b92509c6675b280772..e79a0fdfe80e738fd157ada2f51e59c1a6c12551 100644 (file)
@@ -44,6 +44,7 @@ convert_double_double (void *src,
   return n;
 }
 
+/*
 static long
 copy_strip_1 (int    src_bands,
               void **src,
@@ -73,6 +74,16 @@ copy_strip_1 (int    src_bands,
   return n;
 }
 
+
+*/
+static long
+rgba_to_rgba (void *src,
+              void *dst,
+              long  n)
+{
+  memcpy (dst, src, n * sizeof (double) * 4);
+  return n;
+}
 void
 babl_core_init (void)
 {
@@ -82,13 +93,6 @@ babl_core_init (void)
     "bits",        64,
     NULL);
 
-  babl_conversion_new (
-    babl_type_id (BABL_DOUBLE),
-    babl_type_id (BABL_DOUBLE),
-    "plane",      convert_double_double,
-    NULL
-  );
-
   babl_component_new (
     "R",
     "id", BABL_RED,
@@ -124,10 +128,36 @@ babl_core_init (void)
     babl_component_id (BABL_ALPHA),
     NULL);
 
+  babl_format_new (
+    "id", BABL_RGBA_DOUBLE,
+    babl_model_id (BABL_RGBA),
+    babl_type_id (BABL_DOUBLE),
+    babl_component_id (BABL_RED),
+    babl_component_id (BABL_GREEN),
+    babl_component_id (BABL_BLUE),
+    babl_component_id (BABL_ALPHA),
+    NULL);
+
+  /*
   babl_conversion_new (
     babl_model_id (BABL_RGBA),
     babl_model_id (BABL_RGBA),
     "planar",      copy_strip_1,
     NULL
   );
+  */
+
+  babl_conversion_new (
+    babl_type_id (BABL_DOUBLE),
+    babl_type_id (BABL_DOUBLE),
+    "plane",      convert_double_double,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_model_id (BABL_RGBA),
+    babl_model_id (BABL_RGBA),
+    "linear",      rgba_to_rgba,
+    NULL
+  );
 }
index 1294e1a567ba41c1bd7453177d5d2e4396d4367b..3e70900171f24fe4f32a5c71d4d835358d50b025 100644 (file)
@@ -75,6 +75,13 @@ babl_db_init(void)
   return db;
 }
 
+
+int
+babl_db_count (BablDb *db)
+{
+  return db->count;
+}
+
 void
 babl_db_destroy (BablDb *db)
 {
index caa6866cdf4a1e8dfb58669c0cc0ebb6105313f4..f7e9784dc4632c5e4147d3b30cedb98fe2181c7c 100644 (file)
@@ -31,6 +31,7 @@ void     babl_db_destroy (BablDb           *db);
 void     babl_db_each    (BablDb           *db, 
                           BablEachFunction  each_fun,
                           void             *user_data);
+int      babl_db_count   (BablDb           *db);
 Babl   * babl_db_insert  (BablDb           *db,
                           Babl             *entry);
 Babl   * babl_db_exist   (BablDb           *db,
diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c
new file mode 100644 (file)
index 0000000..491ac6f
--- /dev/null
@@ -0,0 +1,420 @@
+/* babl - dynamically extendable universal pixel fish library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "babl-internal.h"
+
+#define BABL_LEGAL_ERROR 0.000001
+
+typedef struct BablChainContext {
+  Babl  *from;
+  Babl  *to;
+
+  double *best_cost;
+  double *best_loss;
+
+  Babl **chain;
+  int   *conversions;
+
+  Babl **temp_chain;
+  int    temp_conversions;
+
+  int    max_conversions;
+} BablChainContext;
+
+static int
+format_has_alpha (Babl *babl)
+{
+  int i;
+  for (i=0; i<babl->format.components; i++)
+    if (babl->format.component[i]->instance.id == BABL_ALPHA)
+      return 1;
+  return 0;
+}
+
+static int
+format_analytic_loss (Babl *source,
+                      Babl *destination)
+{
+  int loss = 0;
+
+  if (source->format.components <
+      destination->format.components)
+    {
+      loss |= 8;
+    }
+
+  if ( format_has_alpha (source) &&
+      !format_has_alpha (destination))
+    {
+      loss |= 4;
+    }
+
+  if ( BABL(source->format.type[0])->type.bits >
+       BABL(destination->format.type[0])->type.bits)
+    {
+      loss |= 2;
+    }
+
+  if ( source->format.bytes_per_pixel >
+       destination->format.bytes_per_pixel)
+    {
+      loss |= 1;
+    }
+
+
+
+
+  return loss;
+}
+
+
+static int
+chain_gen_each (Babl *babl,
+                void *userdata);
+
+static int
+get_conversion_chain (Babl   *from,
+                      Babl   *to,
+
+                      double *best_cost,
+                      double *best_loss,
+                      Babl  **chain,
+                      int    *conversions,
+
+                      Babl  **temp_chain,
+                      int     temp_conversions,
+
+                      int     max_conversions)
+{
+  BablChainContext context;
+
+  if (temp_conversions>=max_conversions)
+    return 0;
+
+  if (temp_conversions == 0)
+    {
+      /* chain initialization */
+      *conversions = 0;
+      *best_cost   = 200000.0;
+      *best_loss   = 200000.0;
+      chain[0] = NULL;
+      temp_chain[0] = NULL;
+
+      /* Bail out if requesting something stupid (to and from same format, an
+       * optimized memcpy should be used instead (assuming linear buffers).
+       */
+
+      if (from == to)
+         return 0;
+    }
+
+  /* copy parameters to stack */
+  context.from             = from;
+  context.to               = to;
+
+  context.best_cost        = best_cost;
+  context.best_loss        = best_loss;
+  context.chain            = chain;
+  context.conversions      = conversions;
+
+  context.temp_chain       = temp_chain;
+  context.temp_conversions = temp_conversions;
+
+  context.max_conversions  = max_conversions;
+
+  if (temp_conversions == 0)
+    {
+      temp_chain[temp_conversions]=NULL;
+      babl_assert (from);
+      babl_assert (from->class_type == BABL_FORMAT);
+      if (!from->format.from)
+        return 0;
+
+      babl_list_each ((void**) from->format.from,
+                       chain_gen_each,
+                       &context);
+    }
+  else
+    {
+      if (BABL(temp_chain[temp_conversions-1]) &&
+          BABL(temp_chain[temp_conversions-1]->conversion.destination)->
+          format.from)
+
+         babl_list_each (
+           (void **) 
+           BABL(temp_chain[temp_conversions-1]->conversion.destination)->
+           format.from,
+           chain_gen_each,
+           &context);
+    }
+
+  return 0;
+}
+
+static int
+chain_gen_each (Babl *babl,
+                void *userdata)
+{
+  BablChainContext *c = userdata;
+
+  /* fill in the conversion for the chain index we are at */
+  c->temp_chain[c->temp_conversions] = babl;
+
+    {
+      if (BABL(babl->conversion.destination) == c->to)
+        {
+          /* a candidate path has been found */
+        
+          double    temp_cost = 0.0;
+          double    temp_loss = 0.0;
+          double    error     = 1.0;
+          int       analytic_loss = 0;
+          int       i;
+
+          for (i=0; i < c->temp_conversions+1; i++)
+            {
+              error     *= (1.0+c->temp_chain[i]->conversion.error);
+              temp_cost += c->temp_chain[i]->conversion.cost;
+              analytic_loss |= format_analytic_loss (
+                BABL(c->temp_chain[i]->conversion.source),
+                BABL(c->temp_chain[i]->conversion.destination));
+            }
+          temp_loss = analytic_loss;
+          
+          if (error <= (1.0 + BABL_LEGAL_ERROR)  /* we're legal */ &&  
+             
+              /* better than the existing best candidate */ 
+              ( temp_loss <  *c->best_loss ||
+               (temp_loss == *c->best_loss &&
+                temp_cost <  *c->best_cost)))
+            {
+              int i;
+
+              *c->best_cost   = temp_cost;
+              *c->best_loss   = temp_loss;
+              *c->conversions = c->temp_conversions + 1;
+
+              /* copy from temp chain to best chain */
+              for (i = 0.0; i < *c->conversions; i++)
+                 c->chain[i] = c->temp_chain[i];
+            }
+        }
+      else
+        {
+            /* try to add another conversion level in chain,.. */
+            get_conversion_chain (c->from,  /* irrelevant when recalled */
+                                  c->to,
+
+                                  c->best_cost,
+                                  c->best_loss,
+                                  c->chain,
+                                  c->conversions,
+
+                                  c->temp_chain,
+                                  c->temp_conversions + 1,
+
+                                  c->max_conversions);
+        }
+    }
+  return 0;
+}
+
+static inline Babl *
+assert_conversion_find (void *source,
+                        void *destination)
+{
+  int i=0;
+  Babl **conversion;
+
+  conversion = (void*)BABL(source)->type.from;
+  while (conversion && conversion[i])
+    {
+      if (conversion[i]->conversion.destination == destination)
+        return (Babl*)conversion[i];
+      i++;
+    }
+  babl_fatal ("failed, aborting");
+  return NULL;
+}
+
+static char buf[1024];
+static char *
+create_name (Babl *source,
+             Babl *destination,
+             int   is_reference)
+{
+  /* fish names are intentionally kept short */
+  snprintf (buf, 1024, "%s %p %p", "",
+                 source, destination);
+  return buf;
+}
+
+Babl *
+babl_fish_path (Babl   *source,
+                Babl   *destination)
+{
+  Babl *babl = NULL;
+  char *name = create_name (source, destination, 1);
+  Babl *temp_chain[BABL_MAX_PATH_LENGTH];
+
+  babl_assert (BABL_IS_BABL (source));
+  babl_assert (BABL_IS_BABL (destination));
+
+  babl_assert (source->class_type == BABL_FORMAT);
+  babl_assert (destination->class_type == BABL_FORMAT);
+
+  babl                   = babl_calloc (1, sizeof (BablFishPath) +
+                                        strlen (name) + 1);
+  babl->class_type       = BABL_FISH_PATH;
+  babl->instance.id      = 0;
+  babl->instance.name    = ((void *)babl) + sizeof(BablFishPath);
+  strcpy (babl->instance.name, name);
+  babl->fish.source      = (union Babl*)source;
+  babl->fish.destination = (union Babl*)destination;
+
+  babl->fish.processings = 0;
+  babl->fish.pixels      = 0;
+
+  babl->fish_path.cost        = 200000;
+  babl->fish_path.loss        = 200000;
+  babl->fish_path.conversions = 0;
+  babl->fish_path.conversion[0] = NULL;
+
+  babl_assert (source->class_type == BABL_FORMAT);
+  babl_assert (destination->class_type == BABL_FORMAT);
+  
+  get_conversion_chain (source,
+                        destination,
+                        &babl->fish_path.cost,
+                        &babl->fish_path.loss,
+                        (Babl**)(babl->fish_path.conversion),
+                        &babl->fish_path.conversions,
+                        temp_chain,
+                        0, 
+                        BABL_MAX_PATH_LENGTH);
+  if (babl->fish_path.conversions==0)
+    {
+      babl_free (babl);
+      return NULL;
+    }
+  
+  { 
+    Babl *ret = babl_db_insert (babl_fish_db (), babl);
+    if (ret!=babl)
+        babl_free (babl);
+    return ret;
+  }
+}
+
+static long
+chain_process (BablConversion *chain[],
+               int             conversions,
+               void           *source,
+               void           *destination,
+               long            n)
+{
+  void *bufA = NULL;
+  void *bufB = NULL;
+  int   i;
+  
+  babl_assert (source);
+  babl_assert (destination);
+  
+  if (conversions > 1)
+    bufA = babl_malloc (n * sizeof (double) * 5);
+  if (conversions > 2)
+    bufB = babl_malloc (n * sizeof (double) * 5);
+  
+  for (i=0; i<conversions; i++)
+    {
+      if (i==0 && conversions == i+1)
+        {
+          babl_conversion_process ( BABL(chain[i]),
+              source, destination, n);
+        }
+      else if (i == 0)
+        {
+          babl_conversion_process ( BABL(chain[i]),
+              source, bufA, n);
+        }
+      else if (i % 2 == 1)
+        {
+          if (i + 1 == conversions)
+            {
+              babl_conversion_process ( BABL(chain[i]),
+                  bufA, destination, n);
+            }
+          else
+            {
+              babl_conversion_process ( BABL(chain[i]),
+                  bufA, bufB, n);
+            }
+        }
+      else if (i % 2 == 0)
+        {
+          if (i + 1 == conversions)
+            {
+              babl_conversion_process ( BABL(chain[i]),
+                  bufB, destination, n);
+            }
+          else
+            {
+              babl_conversion_process ( BABL(chain[i]),
+                  bufB, bufA, n);
+            }
+        }
+      i ++;
+    }
+  if (bufA)
+    babl_free (bufA);
+  if (bufB)
+    babl_free (bufB);
+
+  return n;
+}
+
+long
+babl_fish_path_process (Babl *babl,
+                        void *source,
+                        void *destination,
+                        long n)
+{
+  /*
+  int i;
+  */
+
+  babl_assert (source);
+  babl_assert (destination);
+/*  
+  babl_log ("path processing from %s to %s",
+            BABL(babl->fish.source)->instance.name,
+            BABL(babl->fish.destination)->instance.name);
+
+  for (i=0; i< babl->fish_path.conversions; i++)
+    babl_log ("\t%s\n",
+             BABL(babl->fish_path.conversion[i])->instance.name);
+*/
+  
+  return chain_process (babl->fish_path.conversion,
+                        babl->fish_path.conversions,
+                        source,
+                        destination,
+                        n);
+}
+
diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c
new file mode 100644 (file)
index 0000000..91acfbc
--- /dev/null
@@ -0,0 +1,338 @@
+/* babl - dynamically extendable universal pixel fish library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "babl-internal.h"
+
+static Babl *
+assert_conversion_find (void *source,
+                        void *destination)
+{
+  Babl *ret = babl_conversion_find (source, destination);
+
+  if (!ret)
+    babl_fatal ("failed, aborting");
+  return ret;
+}
+
+static char buf[1024];
+static char *
+create_name (Babl *source,
+             Babl *destination,
+             int   is_reference)
+{
+  /* fish names are intentionally kept short */
+  snprintf (buf, 1024, "%s %p %p",
+                 is_reference?"ref "
+                             :"",
+                 source, destination);
+  return buf;
+}
+
+
+Babl *
+babl_fish_reference (Babl   *source,
+                     Babl   *destination)
+{
+  Babl *babl = NULL;
+  char *name = create_name (source, destination, 1);
+
+  babl_assert (BABL_IS_BABL (source));
+  babl_assert (BABL_IS_BABL (destination));
+
+  babl_assert (source->class_type == BABL_FORMAT);
+  babl_assert (destination->class_type == BABL_FORMAT);
+
+  babl                   = babl_malloc (sizeof (BablFishReference) +
+                                        strlen (name) + 1);
+  babl->class_type       = BABL_FISH_REFERENCE;
+  babl->instance.id      = 0;
+  babl->instance.name    = ((void *)babl) + sizeof(BablFishReference);
+  strcpy (babl->instance.name, name);
+  babl->fish.source      = (union Babl*)source;
+  babl->fish.destination = (union Babl*)destination;
+
+  babl->fish.processings = 0;
+  babl->fish.pixels      = 0;
+
+  { 
+    Babl *ret = babl_db_insert (babl_fish_db (), babl);
+    if (ret!=babl)
+        babl_free (babl);
+    return ret;
+  }
+}
+
+
+static void
+convert_to_double (BablFormat *source_fmt,
+                   BablImage  *source,
+                   void       *source_buf,
+                   void       *source_double_buf,
+                   int         n)
+{
+  int i;
+
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage*) babl_image (
+      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage*) babl_image (
+      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  dst_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
+  dst_img->pitch[0]  =
+             (dst_img->type[0]->bits/8) * source_fmt->model->components;
+  dst_img->stride[0] = 0;
+
+
+  src_img->data[0]   = source_buf;
+  src_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
+  src_img->pitch[0]  = source_fmt->bytes_per_pixel;
+  src_img->stride[0] = 0;
+
+  /* i is source position */
+  for (i=0 ; i<source_fmt->components; i++)
+    {
+      int j;
+
+      src_img->type[0] = source_fmt->type[i];
+      /* j is source position */
+      for (j=0;j<source_fmt->model->components;j++)
+        {
+          if (source_fmt->component[i] ==
+              source_fmt->model->component[j])
+            {
+              dst_img->data[0] =
+                       source_double_buf + (dst_img->type[0]->bits/8) * j;
+              break;
+            }
+        }
+
+      babl_process (
+           assert_conversion_find (src_img->type[0], dst_img->type[0]),
+           src_img, dst_img,
+           n);
+      src_img->data[0] += src_img->type[0]->bits/8;
+    }
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+
+static void
+convert_from_double (BablFormat *destination_fmt,
+                     void       *destination_double_buf,
+                     BablImage  *destination,
+                     void       *destination_buf,
+                     int         n)
+{
+  int i;
+
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage*) babl_image (
+      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage*) babl_image (
+      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  src_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
+  src_img->pitch[0]  = (src_img->type[0]->bits/8) * destination_fmt->model->components;
+  src_img->stride[0] = 0;
+
+  dst_img->data[0]   = destination_buf;
+  dst_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
+  dst_img->pitch[0]  = destination_fmt->bytes_per_pixel;
+  dst_img->stride    = 0;
+
+  for (i=0 ; i<destination_fmt->components; i++)
+    {
+      int j;
+
+      dst_img->type[0] = destination_fmt->type[i];
+
+      for (j=0;j<destination_fmt->model->components;j++)
+        {
+          if (destination_fmt->component[i] ==
+              destination_fmt->model->component[j])
+            {
+              src_img->data[0] =
+                  destination_double_buf + (src_img->type[0]->bits/8) * j;
+              break;
+            }
+        }
+
+      babl_process (
+           assert_conversion_find (src_img->type[0], dst_img->type[0]),
+           src_img, dst_img,
+           n);
+      dst_img->data[0] += dst_img->type[0]->bits/8;
+    }
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+
+static int
+process_same_model (Babl      *babl,
+                    BablImage *source,
+                    BablImage *destination,
+                    long n)
+{
+  void *double_buf;
+
+  if (BABL_IS_BABL (source) ||
+      BABL_IS_BABL (destination))
+    {
+      babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)",
+                 babl_fish, source, destination, n);
+    }
+
+  double_buf      = babl_malloc(sizeof (double) * n * 
+                              BABL(babl->fish.source)->format.model->components);
+
+  convert_to_double (
+     (BablFormat*) BABL(babl->fish.source),
+     BABL_IS_BABL(source)?source:NULL,
+     BABL_IS_BABL(source)?NULL:source,
+     double_buf,
+     n
+   );
+
+  convert_from_double (
+     (BablFormat*) BABL(babl->fish.destination),
+     double_buf,
+     BABL_IS_BABL(destination)?destination:NULL,
+     BABL_IS_BABL(destination)?NULL:destination,
+     n
+   );
+
+  babl_free (double_buf);
+  return 0;
+}
+
+long
+babl_fish_reference_process (Babl      *babl,
+                             BablImage *source,
+                             BablImage *destination,
+                             long n)
+{
+  void *source_double_buf;
+  void *rgba_double_buf;
+  void *destination_double_buf;
+  Babl *source_image;
+  Babl *rgba_image;
+  Babl *destination_image;
+
+  if (BABL(babl->fish.source)->format.model ==
+      BABL(babl->fish.destination)->format.model)
+        return process_same_model (babl, source, destination, n); 
+  
+  if (BABL_IS_BABL (source) ||
+      BABL_IS_BABL (destination))
+    {
+      babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)",
+                 babl_fish, source, destination, n);
+    }
+
+  source_double_buf      = babl_malloc(sizeof (double) * n * 
+                              BABL(babl->fish.source)->format.model->components);
+  rgba_double_buf        = babl_malloc(sizeof (double) * n * 4);
+  destination_double_buf = babl_malloc(sizeof (double) * n *
+                              BABL(babl->fish.destination)->format.model->components);
+
+  source_image      = babl_image_from_linear (
+      source_double_buf,BABL(BABL((babl->fish.source)) -> format.model));
+  rgba_image        = babl_image_from_linear (
+      rgba_double_buf, babl_model_id (BABL_RGBA));
+  destination_image = babl_image_from_linear (
+      destination_double_buf, BABL(BABL((babl->fish.destination))->format.model));
+
+  convert_to_double (
+     (BablFormat*) BABL(babl->fish.source),
+     BABL_IS_BABL(source)?source:NULL,
+     BABL_IS_BABL(source)?NULL:source,
+     source_double_buf,
+     n
+   );
+
+  {
+    Babl *conv =
+    assert_conversion_find (
+        BABL(babl->fish.source)->format.model,
+        babl_model_id (BABL_RGBA)
+    );
+    if (conv->class_type == BABL_CONVERSION_PLANAR)
+      {
+        babl_process (
+         conv,
+          source_image, rgba_image,
+          n);
+      }
+    else if (conv->class_type == BABL_CONVERSION_LINEAR)
+      {
+        babl_process (
+         conv,
+         source_double_buf, rgba_double_buf,
+         n);
+      }
+    else babl_fatal ("oops");
+  }
+
+  {
+    Babl *conv =
+    assert_conversion_find (
+        babl_model_id (BABL_RGBA),
+        BABL(babl->fish.destination)->format.model);
+    if (conv->class_type == BABL_CONVERSION_PLANAR)
+      {
+        babl_process (
+         conv,
+          rgba_image, destination_image,
+          n);
+      }
+    else if (conv->class_type == BABL_CONVERSION_LINEAR)
+      {
+        babl_process (
+         conv,
+          rgba_double_buf, destination_double_buf,
+          n);
+      }
+    else babl_fatal ("oops");
+  }
+
+  convert_from_double (
+     (BablFormat*) BABL(babl->fish.destination),
+     destination_double_buf,
+     BABL_IS_BABL(destination)?destination:NULL,
+     BABL_IS_BABL(destination)?NULL:destination,
+     n
+   );
+
+  babl_free (source_image);
+  babl_free (rgba_image);
+  babl_free (destination_image);
+
+  babl_free (destination_double_buf);
+  babl_free (rgba_double_buf);
+  babl_free (source_double_buf);
+  return n;
+}
+
diff --git a/babl/babl-fish-simple.c b/babl/babl-fish-simple.c
new file mode 100644 (file)
index 0000000..dc9d62e
--- /dev/null
@@ -0,0 +1,57 @@
+/* babl - dynamically extendable universal pixel fish library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "babl-internal.h"
+
+static char *
+create_name (BablConversion *conversion)
+{
+  return conversion->instance.name;
+}
+
+Babl *
+babl_fish_simple (BablConversion *conversion)
+{
+  Babl *babl = NULL;
+  char *name;
+
+  babl_assert (BABL_IS_BABL (conversion));
+
+  name  = create_name (conversion);
+
+  babl                   = babl_malloc (sizeof (BablFishSimple) +
+                                        strlen (name) + 1);
+  babl->class_type       = BABL_FISH_SIMPLE;
+  babl->instance.id      = 0;
+  babl->instance.name    = ((void *)babl) + sizeof(BablFishSimple);
+  strcpy (babl->instance.name, name);
+  babl->fish.source      = (union Babl*)conversion->source;
+  babl->fish.destination = (union Babl*)conversion->destination;
+
+  babl->fish.processings = 0;
+  babl->fish.pixels      = 0;
+  babl->fish_simple.conversion = conversion;
+
+  { 
+    Babl *ret = babl_db_insert (babl_fish_db (), babl);
+    if (ret!=babl)
+        babl_free (babl);
+    return ret;
+  }
+}
index 2dd6a73acda65c14d7e814b3bf8ba7faf61ac802..50737f362868441a789d402109e05426681e7729 100644 (file)
  */
 
 #include "babl-internal.h"
-#include "babl-db.h"
 #include <string.h>
 #include <stdarg.h>
 
-/*#include "babl-type.h"
-#include "babl-model.h"
-#include "babl-image.h"
-#include "babl-component.h"
-#include "babl-format.h"*/
 
-static int 
-each_babl_fish_destroy (Babl *babl,
-                        void *data)
-{
-  babl_free (babl);
-  return 0;  /* continue iterating */
-}
-
-static char buf[1024];
-static char *
-create_name (Babl *source,
-             Babl *destination,
-             int   is_reference)
-{
-  /* fish names are intentionally kept short */
-  snprintf (buf, 1024, "%s %p %p",
-                 is_reference?"ref "
-                             :"",
-                 source, destination);
-  return buf;
-}
-
-typedef struct SearchData
-{
-  Babl           *source;
-  Babl           *destination;
-  BablConversion *result;
-} SearchData;
-
-Babl *babl_conversion_find2 (void *source,
-                            void *destination)
-{
-  int i=0;
-  Babl **conversion;
-
-  conversion = (void*)BABL(source)->type.from;
-  while (conversion && conversion[i])
-    {
-      if (conversion[i]->conversion.destination == destination)
-        return (Babl*)conversion[i];
-      i++;
-    }
-  babl_fatal ("failed, aborting");
-  return NULL;
-}
-
-
-Babl *babl_conversion_find (void *source,
-                             void *destination)
+static int
+match_conversion (Babl  *conversion,
+                  void  *inout)
 {
-  int i=0;
-  Babl **conversion;
+  void **data = inout;
 
-  conversion = (void*)BABL(source)->type.from;
-  while (conversion && conversion[i])
+  if ((Babl *) conversion->conversion.destination == (Babl*) *data)
     {
-      if (conversion[i]->conversion.destination == destination)
-        return (Babl*)conversion[i];
-      i++;
+      *data = (void *)conversion;
+      return 1;
     }
-  return NULL;
+  return 0;
 }
 
-
-
 Babl *
-babl_fish_reference (Babl *source,
-                     Babl *destination)
+babl_conversion_find (void *source,
+                      void *destination)
 {
-  Babl *babl = NULL;
-  char *name = create_name (source, destination, 1);
-
-  babl_assert (BABL_IS_BABL (source));
-  babl_assert (BABL_IS_BABL (destination));
-
-  babl_assert (source->class_type == BABL_FORMAT);
-  babl_assert (destination->class_type == BABL_FORMAT);
+  void *data=destination;
 
-  babl                   = babl_malloc (sizeof (BablFishReference) +
-                                        strlen (name) + 1);
-  babl->class_type       = BABL_FISH_REFERENCE;
-  babl->instance.id      = 0;
-  babl->instance.name    = ((void *)babl) + sizeof(BablFishReference);
-  strcpy (babl->instance.name, name);
-  babl->fish.source      = (union Babl*)source;
-  babl->fish.destination = (union Babl*)destination;
-
-  babl->fish.processings = 0;
-  babl->fish.pixels      = 0;
-
-  { 
-    Babl *ret = babl_db_insert (db, babl);
-    if (ret!=babl)
-        babl_free (babl);
-    return ret;
-  }
+  babl_list_each ((void*)BABL(source)->type.from, match_conversion, &data);
+  if (data == destination)
+    return NULL;
+  return data;
 }
 
-Babl *
-babl_fish_simple (BablConversion *conversion)
+BablDb *
+babl_fish_db (void)
 {
-  Babl *babl = NULL;
-  char *name;
-
-  babl_assert (BABL_IS_BABL (conversion));
-
-  name  = create_name (BABL(conversion->source),
-                       BABL(conversion->destination),
-                       0);
-
-  babl                   = babl_malloc (sizeof (BablFishSimple) +
-                                        strlen (name) + 1);
-  babl->class_type       = BABL_FISH_SIMPLE;
-  babl->instance.id      = 0;
-  babl->instance.name    = ((void *)babl) + sizeof(BablFishSimple);
-  strcpy (babl->instance.name, name);
-  babl->fish.source      = (union Babl*)conversion->source;
-  babl->fish.destination = (union Babl*)conversion->destination;
-
-  babl->fish.processings = 0;
-  babl->fish.pixels      = 0;
-  babl->fish_simple.conversion = conversion;
-
-  { 
-    Babl *ret = babl_db_insert (db, babl);
-    if (ret!=babl)
-        babl_free (babl);
-    return ret;
-  }
+  if (!db)
+    db = babl_db_init ();
+  return db;
 }
 
 Babl *
 babl_fish (void *source,
-           void *destination)
+           void *destination,
+           ...)
 {
   Babl *source_format      = NULL;
   Babl *destination_format = NULL;
@@ -202,259 +100,103 @@ babl_fish (void *source,
     }
  
  
-  {
-    Babl *shortcut_conversion = babl_conversion_find (source_format, destination_format);
+  if (0)
+    {
+    Babl *shortcut_conversion;
+   
+    shortcut_conversion = babl_conversion_find (
+                                  source_format, destination_format);
 
     if (shortcut_conversion)
       {
         return babl_fish_simple (&(shortcut_conversion->conversion));
       }
   }
-  return babl_fish_reference (source_format, destination_format);
-}
-
-
-static void
-convert_to_double (BablFormat *source_fmt,
-                   BablImage  *source,
-                   void       *source_buf,
-                   void       *source_double_buf,
-                   int         n)
-{
-  int i;
-
-  BablImage *src_img;
-  BablImage *dst_img;
-
-  src_img = (BablImage*) babl_image (
-      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
-  dst_img = (BablImage*) babl_image (
-      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
-
-  dst_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
-  dst_img->pitch[0]  =
-             (dst_img->type[0]->bits/8) * source_fmt->model->components;
-  dst_img->stride[0] = 0;
-
-
-  src_img->data[0]   = source_buf;
-  src_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
-  src_img->pitch[0]  = source_fmt->bytes_per_pixel;
-  src_img->stride[0] = 0;
-
-  /* i is source position */
-  for (i=0 ; i<source_fmt->components; i++)
-    {
-      int j;
-
-      src_img->type[0] = source_fmt->type[i];
-      /* j is source position */
-      for (j=0;j<source_fmt->model->components;j++)
-        {
-          if (source_fmt->component[i] ==
-              source_fmt->model->component[j])
-            {
-              dst_img->data[0] =
-                       source_double_buf + (dst_img->type[0]->bits/8) * j;
-              break;
-            }
-        }
-
-      babl_process (
-           babl_conversion_find2 (src_img->type[0], dst_img->type[0]),
-           src_img, dst_img,
-           n);
-      src_img->data[0] += src_img->type[0]->bits/8;
-    }
-  babl_free (src_img);
-  babl_free (dst_img);
-}
-
-
-static void
-convert_from_double (BablFormat *destination_fmt,
-                     void       *destination_double_buf,
-                     BablImage  *destination,
-                     void       *destination_buf,
-                     int         n)
-{
-  int i;
-
-  BablImage *src_img;
-  BablImage *dst_img;
-
-  src_img = (BablImage*) babl_image (
-      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
-  dst_img = (BablImage*) babl_image (
-      babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
-
-  src_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
-  src_img->pitch[0]  =
-            (src_img->type[0]->bits/8) * destination_fmt->model->components;
-  src_img->stride[0] = 0;
-
-  dst_img->data[0]   = destination_buf;
-  dst_img->type[0]   = (BablType*) babl_type_id (BABL_DOUBLE);
-  dst_img->pitch[0]  = destination_fmt->bytes_per_pixel;
-  dst_img->stride    = 0;
-
-  for (i=0 ; i<destination_fmt->components; i++)
-    {
-      int j;
-
-      dst_img->type[0] = destination_fmt->type[i];
-
-      for (j=0;j<destination_fmt->model->components;j++)
-        {
-          if (destination_fmt->component[i] ==
-              destination_fmt->model->component[j])
-            {
-              src_img->data[0] =
-                  destination_double_buf + (src_img->type[0]->bits/8) * j;
-              break;
-            }
-        }
 
-      babl_process (
-           babl_conversion_find2 (src_img->type[0], dst_img->type[0]),
-           src_img, dst_img,
-           n);
-      dst_img->data[0] += dst_img->type[0]->bits/8;
-    }
-  babl_free (src_img);
-  babl_free (dst_img);
-}
 
+  {
+    Babl *fish_path;
+   
+    fish_path = babl_fish_path (source_format, destination_format);
 
-static int
-process_same_model (Babl      *babl,
-                    BablImage *source,
-                    BablImage *destination,
-                    long n)
-{
-  void *double_buf;
-
-  if (BABL_IS_BABL (source) ||
-      BABL_IS_BABL (destination))
-    {
-      babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)",
-                 babl_fish, source, destination, n);
-    }
-
-  double_buf      = babl_malloc(sizeof (double) * n * 
-                              BABL(babl->fish.source)->format.model->components);
-
-  convert_to_double (
-     (BablFormat*) BABL(babl->fish.source),
-     BABL_IS_BABL(source)?source:NULL,
-     BABL_IS_BABL(source)?NULL:source,
-     double_buf,
-     n
-   );
-
-  convert_from_double (
-     (BablFormat*) BABL(babl->fish.destination),
-     double_buf,
-     BABL_IS_BABL(destination)?destination:NULL,
-     BABL_IS_BABL(destination)?NULL:destination,
-     n
-   );
+    if (fish_path)
+      {
+         return fish_path;
+      }
+  }
 
-  babl_free (double_buf);
-  return 0;
+  return babl_fish_reference (source_format, destination_format);
 }
 
-int
-babl_fish_reference_process (Babl      *babl,
-                             BablImage *source,
-                             BablImage *destination,
-                             long n)
+long
+babl_fish_process (Babl *babl,
+                   void *source,
+                   void *destination,
+                   long  n)
 {
-  void *source_double_buf;
-  void *rgba_double_buf;
-  void *destination_double_buf;
-  Babl *source_image;
-  Babl *rgba_image;
-  Babl *destination_image;
+  BablImage *source_image      = NULL;
+  BablImage *destination_image = NULL;
+  long ret=0;
 
-  if (BABL(babl->fish.source)->format.model ==
-      BABL(babl->fish.destination)->format.model)
-        return process_same_model (babl, source, destination, n); 
-  
-  if (BABL_IS_BABL (source) ||
-      BABL_IS_BABL (destination))
+  switch (babl->class_type)
     {
-      babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)",
-                 babl_fish, source, destination, n);
+      case BABL_FISH_REFERENCE:
+      case BABL_FISH_SIMPLE:
+      case BABL_FISH_PATH:
+
+         if (BABL_IS_BABL (source))
+           source_image = source;
+         if (!source_image)
+           source_image = (BablImage*) babl_image_from_linear (
+                                          source, (Babl*)babl->fish.source);
+         if (BABL_IS_BABL (destination))
+           destination_image = destination;
+         if (!destination_image)
+           destination_image = (BablImage*) babl_image_from_linear (
+                          destination, (Babl*)babl->fish.destination);
+
+         if (babl->class_type == BABL_FISH_REFERENCE)
+           {
+             ret = babl_fish_reference_process (babl, source, destination, n);
+           }
+         else if (babl->class_type == BABL_FISH_PATH)
+           {
+             ret = babl_fish_path_process (babl, source, destination, n);
+           }
+         else if (babl->class_type == BABL_FISH_SIMPLE)
+           { 
+             if (BABL(babl->fish_simple.conversion)->class_type==BABL_CONVERSION_LINEAR)
+               {
+                 ret = babl_conversion_process (BABL(babl->fish_simple.conversion),
+                                                source, destination, n);
+               }
+             else
+               {
+                 ret = babl_conversion_process (BABL(babl->fish_simple.conversion),
+                                              source_image, destination_image, n);
+               }
+           }
+
+        babl_free (source_image);
+        babl_free (destination_image);
+        break;
+      default:
+        babl_log ("NYI");
+        ret = -1;
+        break;
     }
 
-  source_double_buf      = babl_malloc(sizeof (double) * n * 
-                              BABL(babl->fish.source)->format.model->components);
-  rgba_double_buf        = babl_malloc(sizeof (double) * n * 4);
-  destination_double_buf = babl_malloc(sizeof (double) * n *
-                              BABL(babl->fish.destination)->format.model->components);
-
-  source_image      = babl_image_from_linear (
-      source_double_buf,BABL(BABL((babl->fish.source)) -> format.model));
-  rgba_image        = babl_image_from_linear (
-      rgba_double_buf, babl_model_id (BABL_RGBA));
-  destination_image = babl_image_from_linear (
-      destination_double_buf, BABL(BABL((babl->fish.destination))->format.model));
-
-  convert_to_double (
-     (BablFormat*) BABL(babl->fish.source),
-     BABL_IS_BABL(source)?source:NULL,
-     BABL_IS_BABL(source)?NULL:source,
-     source_double_buf,
-     n
-   );
-
-  babl_process (
-    babl_conversion_find2 (
-        BABL(babl->fish.source)->format.model,
-        babl_model_id (BABL_RGBA)
-    ),
-    source_image, rgba_image,
-    n);
-
-  babl_process (
-    babl_conversion_find2 (
-        babl_model_id (BABL_RGBA),
-        BABL(babl->fish.destination)->format.model
-    ),
-    rgba_image, destination_image,
-    n);
-
-  convert_from_double (
-     (BablFormat*) BABL(babl->fish.destination),
-     destination_double_buf,
-     BABL_IS_BABL(destination)?destination:NULL,
-     BABL_IS_BABL(destination)?NULL:destination,
-     n
-   );
-
-  babl_free (source_image);
-  babl_free (rgba_image);
-  babl_free (destination_image);
-
-  babl_free (destination_double_buf);
-  babl_free (rgba_double_buf);
-  babl_free (source_double_buf);
-  return 0;
+  return ret;
 }
 
-int
-babl_fish_process (Babl *babl,
-                   void *source,
-                   void *destination,
-                   long  n)
+static int 
+each_babl_fish_destroy (Babl *babl,
+                        void *data)
 {
-  babl_log ("NYI");
-  return -1;
+  babl_free (babl);
+  return 0;  /* continue iterating */
 }
 
-
-
 BABL_DEFINE_INIT    (fish)
 BABL_DEFINE_DESTROY (fish)
 BABL_DEFINE_EACH    (fish)
index 734932d13bdf815285fcfb8e08c7f4068bb93cb1..4881b049b6ea25cbb3fe89ec51788246a88421d7 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <math.h>
 
 #include "babl-internal.h"
 #include "babl-db.h"
@@ -186,7 +187,7 @@ babl_format_new (void *first_arg,
   BablType        *type      [BABL_MAX_COMPONENTS];
 
   BablSampling    *current_sampling = (BablSampling*) babl_sampling (1,1);
-  BablType        *current_type     = (BablType*)     babl_type_id (BABL_U8);
+  BablType        *current_type     = (BablType*)     babl_type_id (BABL_DOUBLE);
   char            *name             = NULL;
   void            *arg              = first_arg;
 
@@ -240,8 +241,9 @@ babl_format_new (void *first_arg,
               case BABL_CONVERSION_PLANE:
               case BABL_CONVERSION_PLANAR:
               case BABL_FISH:
-              case BABL_FISH_SIMPLE:
               case BABL_FISH_REFERENCE:
+              case BABL_FISH_SIMPLE:
+              case BABL_FISH_PATH:
               case BABL_IMAGE:
               case BABL_EXTENSION:
                 babl_log ("%s unexpected",
@@ -297,4 +299,122 @@ babl_format_new (void *first_arg,
   }
 }
 
+int
+babl_formats_count (void)
+{
+  return babl_db_count (db);
+}
+
+
+Babl *
+babl_format_with_model_as_type (Babl *model,
+                                Babl *type)
+{
+  BablComponent *component[10];
+  int i;
+
+  for (i=0;i<model->model.components;i++)
+    {
+      component[i]= model->model.component[i];
+    }
+  component[i]=NULL;
+
+  return babl_format_new (
+      model,
+      type,
+      component[0],
+      component[1],
+      component[2],
+      component[3],
+      component[4],
+      component[5],
+      component[6],
+      component[7],
+      component[8],
+      component[9],
+      NULL
+   );
+}
+
+#define pixels  256
+
+static double *
+test_create (void)
+{
+  double *test;
+  int     i;
+
+  srandom (20050728);
+  
+  test = babl_malloc (sizeof (double) * pixels * 4);
+
+  for (i = 0; i < pixels * 4; i++)
+     test [i] = (double) random () / RAND_MAX;
+
+  return test;
+}
+
+double
+babl_format_loss (Babl *babl)
+{
+  double  loss = 0.0;
+  double *test;
+  void   *original;
+  double *clipped;
+  void   *destination;
+  double *transformed;
+
+  Babl *ref_fmt;
+  Babl *fmt;
+  Babl *fish_to;
+  Babl *fish_from;
+
+  ref_fmt   = babl_format_new (
+       babl_model ("RGBA"),
+       babl_type ("double"),
+       babl_component ("R"),
+       babl_component ("G"),
+       babl_component ("B"),
+       babl_component ("A"),
+       NULL);
+
+  if (babl->format.loss != -1.0)
+    return babl->format.loss;
+  
+  fmt       = babl; 
+  fish_to   = babl_fish_reference (ref_fmt, fmt);
+  fish_from = babl_fish_reference (fmt, ref_fmt);
+  test        = test_create (); 
+  original    = babl_calloc (pixels, fmt->format.bytes_per_pixel);
+  clipped     = babl_calloc (pixels, ref_fmt->format.bytes_per_pixel);
+  destination = babl_calloc (pixels, fmt->format.bytes_per_pixel);
+  transformed = babl_calloc (pixels,  ref_fmt->format.bytes_per_pixel);
+
+  babl_process (fish_to,   test,        original,    pixels);
+  babl_process (fish_from, original,    clipped,     pixels);
+  babl_process (fish_to,   clipped,     destination, pixels);
+  babl_process (fish_from, destination, transformed, pixels);
+
+  {
+    int i;
+
+    for (i=0;i<pixels*4;i++)
+      {
+        loss += fabs (clipped[i] - test[i]);
+      }
+    loss /= pixels;
+
+  }
+  
+  babl_free (original);
+  babl_free (clipped);
+  babl_free (destination);
+  babl_free (transformed);
+  babl_free (test);
+
+  babl->format.loss = loss;
+  return loss;
+}
+
 BABL_CLASS_TEMPLATE (format)
index 0cde94ecb608eade1fa81d5131acb0168b4a67a1..aacac8a738b60f874f095b3789fc9f68754785a6 100644 (file)
@@ -36,6 +36,7 @@ static const char *class_names[] =
     "BablFish",
     "BablFishReference",
     "BablFishSimple",
+    "BablFishPath",
     "BablImage",
     "BablExtenstion",
     "BablSky"
@@ -73,10 +74,6 @@ babl_die (void)
   exit (-1);
 }
 
-long   babl_conversion_process (Babl *conversion,
-                                void *source,
-                                void *destination,
-                                long  n);
 long
 babl_process (Babl *babl,
               void *source,
@@ -89,78 +86,22 @@ babl_process (Babl *babl,
   babl_assert (BABL_IS_BABL (babl));
   babl_assert (n>0);
 
-  /* these fields are common between conversions and fishes */
-  babl->fish.processings++;
-  babl->fish.pixels += n;
-
   /* matches all conversion classes */
   if (babl->class_type >= BABL_CONVERSION &&
       babl->class_type <= BABL_CONVERSION_PLANAR)
     return babl_conversion_process (babl, source, destination, n);
   
-  if (babl->class_type == BABL_FISH)
-    return babl_fish_process (babl, source, destination, n);
-  
-  if (babl->class_type == BABL_FISH_REFERENCE)
-    {
-       BablImage *source_image      = NULL;
-       BablImage *destination_image = NULL;
-       long ret=0;
-
-       if (BABL_IS_BABL (source))
-         source_image = source;
-       if (!source_image)
-         source_image = (BablImage*) babl_image_from_linear (
-                                        source, (Babl*)babl->fish.source);
-       if (BABL_IS_BABL (destination))
-         destination_image = destination;
-       if (!destination_image)
-         destination_image = (BablImage*) babl_image_from_linear (
-                        destination, (Babl*)babl->fish.destination);
-
-       ret = babl_fish_reference_process (babl, source, destination, n);
-
-       babl_free (source_image);
-       babl_free (destination_image);
-
-       return ret;
-    }
-
-  if (babl->class_type == BABL_FISH_SIMPLE)
+  if (babl->class_type == BABL_FISH ||
+      babl->class_type == BABL_FISH_REFERENCE ||
+      babl->class_type == BABL_FISH_PATH ||
+      babl->class_type == BABL_FISH_SIMPLE)
     {
-       long ret=0;
-       BablImage *source_image      = NULL;
-       BablImage *destination_image = NULL;
-
-       if (BABL_IS_BABL (source))
-         source_image = source;
-       if (!source_image)
-         source_image = (BablImage*) babl_image_from_linear (
-                                        source, (Babl*)babl->fish.source);
-       if (BABL_IS_BABL (destination))
-         destination_image = destination;
-       if (!destination_image)
-         destination_image = (BablImage*) babl_image_from_linear (
-                        destination, (Babl*)babl->fish.destination);
-
-       if (BABL(babl->fish_simple.conversion)->class_type==BABL_CONVERSION_LINEAR)
-         {
-           ret = babl_conversion_process (BABL(babl->fish_simple.conversion),
-                                          source, destination, n);
-         }
-       else
-         {
-           ret = babl_conversion_process (BABL(babl->fish_simple.conversion),
-                                          source_image, destination_image, n);
-         }
-       
-       babl_free (source_image);
-       babl_free (destination_image);
-
-       return ret;
+       babl->fish.processings++;
+       babl->fish.pixels += n;
+       return babl_fish_process (babl, source, destination, n);
     }
 
-  babl_log ("eek");
+  babl_fatal ("eek");
   return -1;
 }
 
@@ -183,3 +124,42 @@ babl_name (Babl *babl)
   babl_assert (BABL_IS_BABL (babl));
   return babl->instance.name;
 }
+
+static int
+each_conversion (Babl *babl,
+                 void *user_data)
+{
+  babl_conversion_error (&babl->conversion);
+  return 0;
+}
+
+static int
+each_format (Babl *babl,
+             void *user_data)
+{
+  babl_format_loss (babl);
+  return 0;
+}
+
+static int
+gen_type_format_for_model (Babl *type, void *userdata)
+{
+  babl_format_with_model_as_type (userdata, type);
+  return 0;
+}
+
+static int
+gen_formats_for_model (Babl *model, void *userdata)
+{
+  babl_type_each (gen_type_format_for_model, model);
+  return 0;
+}
+
+void
+babl_extension_post_load (void)
+{
+  babl_conversion_each (each_conversion, NULL);
+  babl_format_each     (each_format, NULL);
+  babl_model_each (gen_formats_for_model, NULL);
+}
+
index c516f62a6c26984204e98c3e4fe6c1975c3d70cd..6f0973eff68996f7ff829691b520af911bb98b8f 100644 (file)
 #error babl-internal.h included after babl.h
 #endif
 
-#define BABL_MAX_COMPONENTS 32
+#define BABL_MAX_COMPONENTS   32
+#define BABL_MAX_PATH_LENGTH  5
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include "assert.h"
 
+
 #include "babl-classes.h"
 #undef  _BABL_INTERNAL_H
 #include "babl.h"
 #include "babl-memory.h"
 
 
-int    babl_fish_process            (Babl      *babl,
-                                     void      *source,
-                                     void      *destination,
-                                     long       n);
-int    babl_fish_reference_process  (Babl      *babl,
-                                     BablImage *source,
-                                     BablImage *destination,
-                                     long       n);
-Babl * babl_fish_reference          (Babl *source,
-                                     Babl *destination);
-Babl * babl_fish_simple             (BablConversion *conversion);
-Babl * babl_image_from_linear       (void      *buffer,
-                                     Babl      *format);
-Babl * babl_image_double_from_image (Babl      *source);
-void   babl_die                     (void);
-int    babl_sanity                  (void);
-Babl * babl_extension_base          (void);
-
-Babl * babl_extender                (void);
-void   babl_set_extender            (Babl *new_extender);
-
-Babl * babl_extension_quiet_log     (void);
-
-void   babl_core_init               (void);
+Babl   * babl_conversion_find           (void           *source,
+                                         void           *destination);
+double   babl_conversion_error          (BablConversion *conversion);
+long     babl_conversion_process        (Babl           *conversion,
+                                         void           *source,
+                                         void           *destination,
+                                         long            n);
+
+Babl   * babl_extension_base            (void);
+void     babl_extension_post_load       (void);
+
+Babl   * babl_extender                  (void);
+void     babl_set_extender              (Babl           *new_extender);
+
+Babl   * babl_extension_quiet_log       (void);
+
+long     babl_fish_process              (Babl           *babl,
+                                         void           *source,
+                                         void           *destination,
+                                         long            n);
+long     babl_fish_reference_process    (Babl           *babl,
+                                         BablImage      *source,
+                                         BablImage      *destination,
+                                         long            n);
+
+BablDb * babl_fish_db                   (void);
+Babl   * babl_fish_reference            (Babl           *source,
+                                         Babl           *destination);
+Babl   * babl_fish_simple               (BablConversion *conversion);
+Babl   * babl_fish_path                 (Babl           *source,
+                                         Babl           *destination);
+
+long     babl_fish_path_process         (Babl           *babl,
+                                         void           *source,
+                                         void           *destination,
+                                         long            n);
+
+double   babl_format_loss               (Babl           *babl);
+Babl   * babl_image_from_linear         (void           *buffer,
+                                         Babl           *format);
+Babl   * babl_image_double_from_image   (Babl           *source);
+
+double   babl_model_is_symmetric        (Babl           *babl);
+void     babl_die                       (void);
+int      babl_sanity                    (void);
+
+void     babl_core_init                 (void);
+Babl   * babl_format_with_model_as_type (Babl *model,
+                                         Babl *type);
+int      babl_formats_count             (void);  /* should maybe be templated? */
+int      babl_type_is_symmetric         (Babl *babl);
 
 /* FIXME: nasty,. including the symbol even in files where it is
  * not needed,. and a dummy function to use it in those cases
@@ -106,6 +135,7 @@ real_babl_log (const char *file,
   va_end (varg);
 
   fprintf (stdout, "\n");
+  fflush (0);
   return;
   hack_hack ();
 }
@@ -158,7 +188,7 @@ babl_##type_name##_id (int id)                                \
   babl = babl_db_exist (db, id, NULL);                        \
   if (!babl)                                                  \
     {                                                         \
-      babl_log ("%s(%i): not found", __FUNCTION__, id);       \
+      babl_fatal ("%s(%i): not found", __FUNCTION__, id);       \
     }                                                         \
   return babl;                                                \
 }
index 685dbf10a0f5d105d409d827447dd102707b4673..ea6a4ecc33b38686f37c0d914af21b64854c8c29 100644 (file)
@@ -165,6 +165,7 @@ conversion_introspect (Babl *babl)
 {
   babl_log ("\t\tprocessings:%i pixels:%li",
             babl->conversion.processings, babl->conversion.pixels);
+  babl_log ("\t\tcost: %i   error: %f", babl->conversion.cost, babl->conversion.error);
 }
 
 static void
index f48779e0995f8450f12f78d9b3f2de54319a6cbd..6e5428d9d369c0af43187c6c1af063bf2453ff2b 100644 (file)
@@ -20,6 +20,7 @@
 #include "babl-internal.h"
 #include <string.h>
 #include <stdarg.h>
+#include <math.h>
 #include "babl-db.h"
 
 
@@ -125,8 +126,9 @@ babl_model_new (void *first_argument,
               case BABL_CONVERSION_PLANE:
               case BABL_CONVERSION_PLANAR:
               case BABL_FISH:
-              case BABL_FISH_REFERENCE:
               case BABL_FISH_SIMPLE:
+              case BABL_FISH_REFERENCE:
+              case BABL_FISH_PATH:
               case BABL_IMAGE:
               case BABL_EXTENSION:
                 babl_log ("%s unexpected", babl_class_name (babl->class_type));
@@ -168,4 +170,144 @@ babl_model_new (void *first_argument,
   }
 }
 
+
+#define TOLERANCE 0.001
+
+#define pixels    512
+
+static double *
+test_create (void)
+{
+  double *test;
+  int     i;
+  
+  srandom (20050728);
+
+  test = babl_malloc (sizeof (double) * pixels * 4);
+
+  for (i = 0; i < pixels * 4; i++)
+     test [i] = ((double) random () / RAND_MAX ) * 1.4 - 0.2;
+
+  return test;
+}
+
+static Babl *reference_format (void)
+{
+  static Babl *self = NULL;
+  
+  if (!self)
+     self = babl_format_new (
+       babl_model ("RGBA"),
+       babl_type ("double"),
+       babl_component ("R"),
+       babl_component ("G"),
+       babl_component ("B"),
+       babl_component ("A"),
+       NULL);
+  return self;
+}
+
+static Babl *construct_double_format (Babl *model)
+{
+  void *argument[42+1];
+  int   args = 0;
+  int   i;
+
+  argument[args++] = model;
+  argument[args++] = babl_type ("double");
+
+  for (i=0;i<model->model.components; i++)
+    {
+      argument[args++] = model->model.component[i];
+    }
+  argument[args++] = NULL;
+
+#define o(argno) argument[argno],
+  return babl_format_new (o(0)  o(1)  o(2)  o(3)
+                          o(4)  o(5)  o(6)  o(7)
+                          o(8)  o(9) o(10) o(11)
+                         o(12) o(13) o(14) o(15)
+                         o(16) o(17) o(18) o(19) 
+                         o(20) o(21) o(22) o(23) 
+                         o(24) o(25) o(26) o(27)
+                         o(28) o(29) o(30) o(31)
+                         o(32) o(33) o(34) o(35)
+                         o(36) o(37) o(38) o(39) 
+                         o(40) o(41) o(42) NULL);
+#undef o
+}
+
+double 
+babl_model_is_symmetric (Babl *babl)
+{
+  double *test;
+  void   *original;
+  double *clipped;
+  void   *destination;
+  double *transformed;
+  int     symmetric=1;
+
+  Babl *ref_fmt;
+  Babl *fmt;
+  Babl *fish_to;
+  Babl *fish_from;
+
+  test      = test_create ();
+  ref_fmt   = reference_format ();
+  fmt       = construct_double_format (babl);
+  fish_to   = babl_fish_reference (ref_fmt, fmt);
+  fish_from = babl_fish_reference (fmt, ref_fmt);
+  
+  original    = babl_calloc (1,64/8 * babl->model.components * pixels);
+  clipped     = babl_calloc (1,64/8 * 4 * pixels);
+  destination = babl_calloc (1,64/8 * babl->model.components * pixels);
+  transformed = babl_calloc (1,64/8 * 4 * pixels);
+
+  babl_process (fish_to,   test,        original,    pixels);
+  babl_process (fish_from, original,    clipped,     pixels);
+  babl_process (fish_to,   clipped,     destination, pixels);
+  babl_process (fish_from, destination, transformed, pixels);
+
+  {
+    int i;
+    int log=0;
+
+    for (i=0;i<pixels;i++)
+      {
+        int j;
+        for (j=0;j<4;j++)
+           if (fabs (clipped[i*4+j] - transformed[i*4+j])>TOLERANCE)
+             {
+                if (!log)
+                  log=1;
+                symmetric=0;
+             }
+        if (log && log < 5)
+          {
+            babl_log ("%s", babl->instance.name);
+            babl_log ("\ttest:     %2.3f %2.3f %2.3f %2.3f", test [i*4+0],
+                                                             test [i*4+1],
+                                                             test [i*4+2],
+                                                             test [i*4+3]);
+            babl_log ("\tclipped:  %2.3f %2.3f %2.3f %2.3f", clipped [i*4+0],
+                                                             clipped [i*4+1],
+                                                             clipped [i*4+2],
+                                                             clipped [i*4+3]);
+            babl_log ("\ttrnsfrmd: %2.3f %2.3f %2.3f %2.3f", transformed [i*4+0],
+                                                             transformed [i*4+1],
+                                                             transformed [i*4+2],
+                                                             transformed [i*4+3]);
+            log++;
+          }
+      }
+  }
+  
+  babl_free (original);
+  babl_free (clipped);
+  babl_free (destination);
+  babl_free (transformed);
+  babl_free (test);
+  return symmetric;
+}
+
 BABL_CLASS_TEMPLATE (model)
index 4f7c33e35e60ca1ea83ffa00b015250ce1ee664a..b0e7b612f31b90655d792e3d5f4a2e998a7e731f 100644 (file)
@@ -104,7 +104,7 @@ static int
 id_sanity (Babl *babl,
            void *user_data)
 {
-  if (0 == babl->instance.id &&
+  if (0 && 0 == babl->instance.id &&
       babl->instance.creator &&
       !strcmp(BABL(babl->instance.creator)->instance.name, "BablBase"))
     {
index 9edeeeeef10bd2bc1f2606f85e4c270a730163b2..81d270ee9031aba10dbfe7d78bf796c2d09f90d6 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <math.h>
 
 #include "babl-internal.h"
 #include "babl-db.h"
@@ -138,4 +139,102 @@ babl_type_new (void *first_arg,
   }
 }
 
+
+#define TOLERANCE 0.000000001
+#define samples   512
+
+double test[samples];
+
+double r_interval (double min, double max)
+{
+  long int rand_i = random ();
+  double ret;
+  ret = (double) rand_i / RAND_MAX;
+  ret*=(max-min);
+  ret+=min;
+  return ret;
+}
+
+void test_init (double min, double max)
+{
+  int i;
+  srandom (20050728);
+  for (i=0;i<samples;i++)
+    {
+      test [i]=r_interval(min,max);
+    }
+}
+
+
+static Babl *double_vector_format (void)
+{
+  static Babl *self = NULL;
+  
+  if (!self)
+     self = babl_format_new (
+       babl_model ("Y"),
+       babl_type ("double"),
+       babl_component ("Y"),
+       NULL);
+  return self;
+}
+
+int
+babl_type_is_symmetric (Babl *babl)
+{
+  int     is_symmetrical=1;
+  void   *original;
+  double *clipped;
+  void   *destination;
+  double *transformed;
+
+  Babl *ref_fmt;
+  Babl *fmt;
+  Babl *fish_to;
+  Babl *fish_from;
+
+  test_init (0.0, 182.0);
+  
+  ref_fmt = double_vector_format ();
+  fmt = babl_format_new (babl_model ("Y"),
+                         babl,
+                         babl_component ("Y"),
+                         NULL);
+  fish_to   = babl_fish_reference (ref_fmt, fmt);
+  fish_from = babl_fish_reference (fmt, ref_fmt);
+  
+  original    = babl_calloc (1,babl->type.bits/8 * samples);
+  clipped     = babl_calloc (1,64/8              * samples);
+  destination = babl_calloc (1,babl->type.bits/8 * samples);
+  transformed = babl_calloc (1,64/8              * samples);
+  
+  babl_process (fish_to,   test,        original,    samples);
+  babl_process (fish_from, original,    clipped,     samples);
+  babl_process (fish_to,   clipped,     destination, samples);
+  babl_process (fish_from, destination, transformed, samples);
+
+  {
+    int cnt=0;
+    int i;
+    for (i=0;i<samples;i++)
+      {
+        if (fabs (clipped[i] - transformed[i])> TOLERANCE)
+          {
+            if (cnt++<4)
+            babl_log ("%s:  %f %f %f)",
+             babl->instance.name, test[i], clipped[i], transformed[i]
+             );
+            is_symmetrical=0;
+          }
+      }
+  }
+  
+  babl_free (original);
+  babl_free (clipped);
+  babl_free (destination);
+  babl_free (transformed);
+
+  return is_symmetrical;
+}
+
 BABL_CLASS_TEMPLATE (type)